/*
 * calculation_server.cpp
 *
 *  Created on: Jun 22, 2011
 *      Author: Gilad & Yotam
 */

#include "calculation_server.h"
#include "solveEquationSystem.h"
#include "similarity.h"
#include "polynomial.h"
#include "mtm.h"

typedef mtm::shared_ptr<Job> JobPtr;

class CompareJobId {
	//this class will use when searching a job with certain id in the list
	int id;
public:
	CompareJobId(const int& id) : id(id) {}
	bool operator()(JobPtr& currentJob) const {
		return id == currentJob->getId();
	}
};

class CompareJobPriority {
	/*
	 * this class will be used for arranging the list from the first
	 * job to preform to the last one
	 */
public:
	bool operator()(JobPtr& first, JobPtr& second) const {
		if (first->getPriority() == second->getPriority()) {
			return (first->getId() < second->getId());
		}
		return (first->getPriority() > second->getPriority());
	}
};


CalculationServer::CalculationServer() :
	jobList(), counter(0) {
}

int CalculationServer::addJob(JobType type, int priority, const Matrix& A,
		const Matrix& B) {
	try {
		switch (type) {
		case (SOLVE_EQUATION_SYSTEM): {
			jobList.insert(JobPtr(new SolveEquationSystem(counter, priority, A,
					B)), jobList.begin());
			break;
		}
		case (SIMILARITY): {
			jobList.insert(JobPtr(new Similarity(counter, priority, A, B)),
					jobList.begin());
			break;
		}
		case (POLYNOMIAL): {
			jobList.insert(JobPtr(new Polynomial(counter, priority, A, B)),
					jobList.begin());
			break;
		}
		}
	} catch (Job::InvalidJobPriority&) {
		throw CalculationServer::InvalidPriority();
	}
	return counter++;
}

void CalculationServer::removeJob(int jobIndex) {
	Iterator<JobPtr> jobToRemove = jobList.find(CompareJobId(jobIndex));
	try {
		jobList.remove(jobToRemove);
	} catch (ListExceptions::ElementNotFound&) {
		throw CalculationServer::JobNotFound();
	}
}

void CalculationServer::changePriority(int jobIndex, int newPriority) {
	Iterator<JobPtr> jobToChange = jobList.find(CompareJobId(jobIndex));
	try {
		(**jobToChange).changePriority(newPriority);
	} catch (ListExceptions::ElementNotFound&) {
		throw CalculationServer::JobNotFound();
	} catch (Job::InvalidJobPriority&) {
		throw CalculationServer::InvalidPriority();
	}
}

Matrix CalculationServer::execute() {
	jobList.sort(CompareJobPriority());
	Iterator<JobPtr> jobToExecute = jobList.begin();
	try {
		Matrix solution = jobToExecute.operator*()->execute();
		jobList.remove(jobList.begin());
		return solution;
	} catch (ListExceptions::ElementNotFound&) {
		throw CalculationServer::JobNotFound();
	}
	catch (...) {
		// if failed for any other reason:
		throw CalculationServer::OperationFailed();
	}
}


int CalculationServer::nextJob() {
	jobList.sort(CompareJobPriority());
	try {
		return jobList.begin().operator*()->getId();
	} catch (ListExceptions::ElementNotFound&) {
		throw CalculationServer::JobNotFound();
	}
}

int CalculationServer::totalJobs() {
	return jobList.getSize();
}
